package main.test.SparkAPI.Baics.classApi

object testTraits {
  /**
   * Declare an interface using a tait
   * Implement class, object, and trait that conform ot
   * one or more interfaces
   * Define a closed set of values suing sealed traits
   * Now that you discovered singleton objcts in lesson 11, let us learn
   * about trait.
   * Earlier in this book, we see that
   * a class can hve up to one superclass; you cannot express multiple
   * inheritance using classes and abstract classes.
   * Traits are very similar to abstract classes but
   * with a fundamental difference: A class can inherit from one or more
   * traits. you can use them to express multiple inheritance; you cannot achieve
   * the same with abstract class.You can use traits to define
   * interfaces to represent a set features
   * (hence the name traits) that your class must have.
   * This is a key object-oriented concept that find in many languages
   * such as Go, Kotlin and java. In future units,
   * you will learn that trait are a lot more than just
   * a way to express an interface: some of their superpowers and why this
   * make them a more expressive and powerful
   * tool. In this lesson find how create a trait and implement classes object, and other interfaces that conform
   * to one or more interfaces. learn about
   * sealed traits: allow you to define a closed set of implementations for
   * your interface that compiler guarantees at compiler time.
   * find the enumeration syntax that Scala3 introduces as an alternative to sealed traits
   * use App trait to implement the entry point of your app.
   *
   *
   */


  //defining traits
  /**
   * need to represent a zoo's animals and make sure they have some common behavior: they
   * all sleep, eat and move.
   * Let define an interface to enforce these functionalities.
   */
  trait Animal{
    def sleep = "ZzZ"

    def eat(food:String):String

    def move(x:Int, y:Int):String


  }

  /**
   * use keyword trait and a name to identify an interface.
   * SCALA2,trait can have abstract and fulled implemented coding elements
   * such as functions, values,and variables.
   *
   */
    trait Nameable{
    def name:String
  }

  /**
   * from scala3, a trait can hve parameters.
   * you cna define trait Nbl as follow
   *
   */

//    trait Nbl(name:String)
trait Printable{
    def print():Unit
  }

  class Cat extends Animal{
    //    You are redefining a fully
    //    implemented function, so
    //    you must use the keyword
    //    override.
    override def sleep: String = "Sleepy cat!!"


    //    You can omit the keyword override because
    //    you are providing an implementation
    //    for an abstract function
    def eat(food: String): String = s"the cat is eating $food !!!"

    def move(x: Int, y: Int): String = s"the cat is moving to ($x, $y)"
  }

    //  In Scala, you can define a coding element that inherits from an interface using the keyword
    //  extends; if you need to conform to more than one trait, you can do so using the
    //  keyword with.
  class Dog(val name:String) extends Animal with Nameable{
    override def eat(food: String): String = s"$food $food"
    override def move(x: Int, y: Int): String = s"let's go to ($x, $y)!"
  }
  val tiggerTheDog = new Dog("Tigger")
  val cat  = new Cat

  def feedTreat(animal:Animal) =
    animal.eat("treat")


  def welcome(nameable: Nameable) =
    println(s"Hi, ${nameable.name}!")

  /**
   * In lesson 11, you learned scala identifies a program's
   * entry pints by looking for main fucntion with a specific
   * signature.
   * folloing provding an exaple of an excutable obj:
   * def HelloWorld{
   * def main(args:Array[String[):Unit =
   * println("Hello world)
   * }
   *
   * achieve it by extending App.
   * This trait is part of the standard Scala packages: THe compiler
   * automatically add it into your
   * scope without adding an iport instruction.
   * The trait App makes wrting application
   * entry points much more straightforward and concise:
   * It automtically includes a main fuction with the correct
   * sig to ensure that the compiler detects your obj as an entry
   * point. THanks to the App, you rewrite the previous code as follows:
   *
   * object HelloWorld extends App {
   *    println("Hello world")
   *    }
   */


  /**
   * Let us consider implementation of all suits in a
   * deck of cards using enumeration.
   *
   *
   */
    def testSuitUDF()={
      println(SuitUDF.myClub)


    }

  def testTimeFunc() = {


  }

  def main(args: Array[String]): Unit = {
    println(feedTreat(tiggerTheDog))
    println(feedTreat(cat))

    welcome(tiggerTheDog)
//    welcome(cat)
    testSuitUDF()





  }

}
